Function.RegisterNamespace("Test.System.Script");

[Fixture]
Test.System.Script.DelayedConstructor=function(){
    [Fixture]
    function DelayedConstructor(){
        [Fact]
        function DoesNotThrowIfConstructorIsAValidFunction(){
            var constructor=function(){};
            
            var actual=Record.Exception(function(){
                System.Script.DelayedConstructor(new constructor(),constructor);
            });
            
            Assert.Null(actual);
        }

        [Fact]
        function ThrowsIfConstructorIsOmitted(){
            var expected="System.Script.DelayedConstructor: 'constructor' must be a valid Function pointer.";
            
            var actual=Record.Exception(function(){
                System.Script.DelayedConstructor(null);
            });
            
            Assert.Equal(expected,actual);
        }

        [Fact]
        function ThrowsIfConstructorIsUndefined(){
            var expected="System.Script.DelayedConstructor: 'constructor' must be a valid Function pointer.";
            
            var actual=Record.Exception(function(){
                System.Script.DelayedConstructor(null,undefined);
            });
            
            Assert.Equal(expected,actual);        
        }

        [Fact]
        function ThrowsIfConstructorIsNull(){
            var expected="System.Script.DelayedConstructor: 'constructor' must be a valid Function pointer.";
            
            var actual=Record.Exception(function(){
                System.Script.DelayedConstructor(null,null);
            });
            
            Assert.Equal(expected,actual);
        }

        [Fact]
        function ThrowsIfConstructorIsNotAValidFunction(){
            var expected="System.Script.DelayedConstructor: 'constructor' must be a valid Function pointer.";
            
            var actual=Record.Exception(function(){
                System.Script.DelayedConstructor(null,{});
            });
            
            Assert.Equal(expected,actual);
        }

        [Fact]
        function DoesNotThrowIfCallbackIsOmitted(){
            var constructor=function(){};
        
            var actual=Record.Exception(function(){
                System.Script.DelayedConstructor(new constructor(),constructor);
            });
            
            Assert.Null(actual);
        }

        [Fact]
        function DoesNotThrowIfCallbackIsUndefined(){
            var constructor=function(){};

            var actual=Record.Exception(function(){
                System.Script.DelayedConstructor(new constructor(),constructor,undefined);
            });
            
            Assert.Null(actual);
        }

        [Fact]
        function DoesNotThrowIfCallbackIsNull(){
            var constructor=function(){};

            var actual=Record.Exception(function(){
                System.Script.DelayedConstructor(new constructor(),constructor,null);
            });
            
            Assert.Null(actual);
        }

        [Fact]
        function DoesNotThrowIfCallbackIsAValidFunction(){
            var constructor=function(){};
            
            var actual=Record.Exception(function(){
                System.Script.DelayedConstructor(new constructor(),constructor,function(){});
            });
            
            Assert.Null(actual);
        }

        [Fact]
        function ThrowsIfCallbackIsNotAValidFunction(){
            var expected="System.Script.DelayedConstructor: 'callback' must be a valid Function pointer.";
            
            var actual=Record.Exception(function(){
                System.Script.DelayedConstructor(null,function(){},{});
            });
            
            Assert.Equal(expected,actual);
        }
        
        [Fact]
        function CallsCallbackIfInvokedInNewScope(){
            var callback=function(){
                actual=true;
            }
            var actual=false;
            
            new function(){
                return System.Script.DelayedConstructor(this,arguments.callee,callback);
            }
            
            Assert.True(actual);            
        }

        [Fact]
        function SetsScopeForCallbackIfInvokedInNewScope(){
            var callback=function(){
                actual=this;
            }
            var actual=null;
            var expected={expected:"expected"};
            
            new function(){
                expected.constructor=arguments.callee;
                return System.Script.DelayedConstructor(expected,expected.constructor,callback);
            }
            
            Assert.Equal(expected,actual);            
        }

        [Fact]
        function PassesArgumentsToCallbackIfInvokedInNewScope(){
            var callback=function(arg1,arg2,argN){
                actual=Array.prototype.slice.call(arguments,0);
            }
            var actual=null;
            var expected=["expected1","expected2","expected3"];
            
            new function(){
                return System.Script.DelayedConstructor(this,arguments.callee,callback,expected);
            }
            
            Assert.Equal(expected,actual);            
        }

        [Fact]
        function ReturnsScopeIfInvokedInNewScope(){
            var expected={expected:"expected"};

            var actual=new function(){
                expected.constructor=arguments.callee;
                return System.Script.DelayedConstructor(expected,arguments.callee,function(){});
            }
            
            Assert.Equal(expected,actual);            
        }
        
        [Fact]
        function ReturnsRawConstructorIfNotPassedPreloadArguments(){
            var expected=function(){};

            var actual=new function(){
                return System.Script.DelayedConstructor(this,expected);
            }
            
            Assert.Equal(expected,actual);            
        }
       
        [Fact]
        function PassesPreloadArgumentToDelayedConstructor(){
            var target=function(targetArgument){
                actual=targetArgument;
            };
            var actual=null;
            var expected="expected";

            new System.Script.DelayedConstructor({},target,null,[expected])();
            
            Assert.Equal(expected,actual);            
        }

        [Fact]
        function PassesPreloadArgumentsToDelayedConstructor(){
            var target=function(targetArgument){
                actual=Array.prototype.slice.call(arguments,0);
            };
            var actual=null;
            var expected=["expected1","expected2"];

            new System.Script.DelayedConstructor({},target,null,expected)();
            
            Assert.Equal(expected,actual);
        }
    }
}